module CalHelper
  
  def calendar(options = {})
        
    raise(ArgumentError, "No year given")  unless options.has_key?(:year)
    raise(ArgumentError, "No month given") unless options.has_key?(:month)

    # Date.const_set "MONTHNAMES", [nil] + %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember)
    # Date.const_set "ABBR_MONTHNAMES", [nil] + %w(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez)
    # Date.const_set "DAYNAMES", %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag)
    # Date.const_set "ABBR_DAYNAMES", %w(So Mo Di Mi Do Fr Sa)

    defaults = {
      :table_class => 'calendar',
      :month_name_class => 'monthName',
      :other_month_class => 'otherMonthDay',
      :day_name_class => 'dayName',
      :day_class => 'day',
      :abbrev => (0..1),
      :first_day_of_week => 1
    }
    options = defaults.merge options

    first_day_of_month = Date.civil(options[:year], options[:month], 1)
    last_day_of_month = Date.civil(options[:year], options[:month], -1)

    first_weekday = first_day_of_week(options[:first_day_of_week])
    last_weekday = last_day_of_week(options[:first_day_of_week])
    
    day_names = Date::ABBR_DAYNAMES.dup
    first_weekday.times do
      day_names.push(day_names.shift)
    end

    # Print table heading with month name
    cal = %(<table class="#{options[:table_class]}" border="0" cellspacing="0" cellpadding="0">) 
    cal << %(<thead><tr class="#{options[:month_name_class]}"><th colspan="7">#{Date::MONTHNAMES[options[:month]]} #{options[:year]}</th></tr><tr class="#{options[:day_name_class]}">)
    
    # Print day names
    day_names.each {|dayname| cal << "<th>#{dayname[options[:abbrev]]}</th>"}
    cal << "</tr></thead><tbody><tr>"
    
    # Print days of previous month
    beginning_of_week(first_day_of_month, first_weekday).upto(first_day_of_month - 1) do |day|
      cal << %(<td class="#{options[:other_month_class]})
      cal << " weekendDay" if weekend?(day)
      cal << %(">#{day.day}</td>)
    end unless first_day_of_month.wday == first_weekday
    
    # Settings für Kalender #1 abrufen
    @sets = Setting.find_first(["cal_id = ?", 1]) #1
    
    date_length = @sets.date_length * 60  
    available_dates_count = 0
    
    i = @sets.day_starts - date_length
    while i <= (@sets.break_starts - date_length)
      i += date_length
      available_dates_count += 1
    end
    
    i = @sets.break_ends - date_length
    while i <= (@sets.day_ends - date_length)
      i += date_length
      available_dates_count += 1
    end
    
    available_dates_count -= 1
    
    # Print all days of the current month
    first_day_of_month.upto(last_day_of_month) do |current_day|
      
      cell_attrs ||= {:class => options[:day_class]}     
      
      # if [0, 6].include?(current_day.wday)
      if weekend?(current_day)
        cell_attrs[:class] += " weekendDay"
        day_label = current_day.mday
      else
        cell_attrs[:class] += " dateDay"
        day_label = link_to current_day.mday, :action => "view", :id => current_day
      end
      
      @termin = Termin.count(["DATE(date_begin) = ?", current_day])
      if @termin != 0
        cell_attrs[:class] += " bookedDay"
      end
      if @termin >= available_dates_count
        cell_attrs[:class] += " bookedOutDay"
      end
      if current_day == Date.today
        cell_attrs[:class] += " currentDay"
      end
      
      cell_attrs = cell_attrs.map {|key, value| %(#{key}="#{value}") }.join(" ")
      cal << "<td #{cell_attrs}>#{day_label}</td>"
      cal << "</tr><tr>" if current_day.wday == last_weekday
    end
    
    # Print days of next month
    (last_day_of_month + 1).upto(beginning_of_week(last_day_of_month + 7, first_weekday) - 1)  do |day|
      cal << %(<td class="#{options[:other_month_class]})
      cal << " weekendDay" if weekend?(day)
      cal << %(">#{day.day}</td>)
    end unless last_day_of_month.wday == last_weekday
    
    d15 = Time.mktime(options[:year], options[:month], 15)
    next_month = (d15 + 2592000).strftime("%Y-%m")
    prev_month = (d15 - 2592000).strftime("%Y-%m")
    this_month = Date.today.strftime("%Y-%m")
    
    cal << "</tr><tr>"
    cal << "<td colspan=\"7\">"
    cal << "Gehe zu: "
    cal << (link_to "Aktueller Monat", :id => this_month)
    cal << " | " + (link_to "Vorheriger Monat", :id => prev_month)
    cal << " | " + (link_to "Nächster Monat", :id => next_month)
    cal << "</td></tr>"
    cal << "<tr><td colspan=\"7\">"
    cal << "<br>Legende: <span class=dateDay>Freier Tag</span>"
    cal << " <span class=bookedDay>Teilweise gebuchter Tag</span>"
    cal << " <span class=bookedOutDay>Ausgebuchter Tag</span>"
    cal << "</td></tr>"
    cal << "</tbody></table>"  
  end
  
  def view(day)
    # Aktuellen Tag aus der URL in Jahr, Monat, Tag aufteilen
    d = day.split("-")

    # Settings für Kalender #1 abrufen
    @settings = Setting.find_first(["cal_id = ?", 1]) #1
    ds = @settings.day_starts.strftime("%H:%M").split(":")
    de = @settings.day_ends.strftime("%H:%M").split(":")
    bs = @settings.break_starts.strftime("%H:%M").split(":")
    be = @settings.break_ends.strftime("%H:%M").split(":")
    
    # Settings-Variablen setzen
    day_starts = Time.mktime(d[0], d[1], d[2], ds[0], ds[1])
    day_ends = Time.mktime(d[0], d[1], d[2], de[0], de[1])
    break_starts = Time.mktime(d[0], d[1], d[2], bs[0], bs[1])
    break_ends = Time.mktime(d[0], d[1], d[2], be[0], be[1])
    date_length = @settings.date_length * 60
    cur_time = day_starts
        
    # Kalender anzeigen
    ansicht = "<table class=\"dayview\">\n"
    today = Time.mktime(d[0], d[1], d[2])
    ansicht << "<tr><th colspan=\"2\">#{today.strftime("%A, %d. %B %Y")}</th></tr>"
    # Solange Zeit < Tagesende - Terminlänge
    while cur_time <= (day_ends - date_length) do
      # Uhrzeit anzeigen
      ansicht << "<tr class=\"#{cycle("even", "odd")}\"><td>#{cur_time.strftime("%H:%M")}</td><td>\n"
      # Mittagspause anzeigen
      if cur_time > (break_starts - date_length) and cur_time < break_ends
        ansicht << " Mittagspause"
        cur_time = break_ends - date_length
      else
        # Termindaten auslesen
        @termin = Termin.find_first(["DATE(date_begin) = ? AND date_begin >= ? AND date_begin < ?", day, cur_time, (cur_time + date_length)])
        # Termindaten anzeigen, wenn vorhanden
        if @termin
          ansicht << " Patient ID: " + @termin.patient_id.to_s
        else
          if cur_time > Time.now
            # Link: Buchen anzeigen
            ansicht << " " + (link_to "Reservieren", {:action => "book", :id => cur_time.strftime("%Y-%m-%dT%H.%M")})
          end
        end
      end
      cur_time += date_length
      ansicht << "</td></tr>\n"
    end
    
    # Link zurück zur Monatsansicht
    ansicht << "<tr><td colspan=\"2\"><br></td></tr>"
    ansicht << "<tr><td colspan=\"2\">"
    ansicht << (link_to "Zurück zur Monatsansicht", :action => "browse", :id => cur_time.strftime("%Y-%m"))
    ansicht << "</td></tr></table>"
    # Tagesansicht zurückgeben
    return ansicht
  end
  
  private
  
  def first_day_of_week(day)
    day
  end
  
  def last_day_of_week(day)
    if day > 0
      day - 1
    else
      6
    end
  end
  
  def days_between(first, second)
    if first > second
      second + (7 - first)
    else
      second - first
    end
  end
  
  def beginning_of_week(date, start = 1)
    days_to_beg = days_between(start, date.wday)
    date - days_to_beg
  end
  
  def weekend?(date)
    [0, 6].include?(date.wday)
  end
  
end
